package com.jiangli.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jiangli.constant.*;
import com.jiangli.context.BaseContext;
import com.jiangli.dto.*;
import com.jiangli.entity.User;
import com.jiangli.exception.BaseException;
import com.jiangli.exception.LoginFailedException;
import com.jiangli.mapper.UserMapper;
import com.jiangli.properties.WeChatProperties;
import com.jiangli.result.PageResult;
import com.jiangli.result.Result;
import com.jiangli.service.UserService;
import com.jiangli.utils.HttpClientUtil;
import com.jiangli.utils.PasswordEncoder;
import com.jiangli.vo.UserLoginVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.security.Key;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.jiangli.controller.user.UserController.validateQQEmail;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
    private static final String USER_REGISTER_ERROR = "用户注册失败";
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WeChatProperties Wxproperties;
    @Value("${spring.mail.username}")
    private String sendMailer;
    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private ObjectMapper objectMapper;
    //永久层 openid——>id
    private static final String USER_LOGIN = "user:login:openid";//用于微信用户登录
    //长久层 长久存储用户信息 30Min
    private static final String USER_INFO = "user:info:id";
    @Autowired
    private UserService userService;


    public User wxLogin(UserLoginDTO userLoginDTO) {
        //调用微信接口 根据code获取open——ID
        String openid = getOpenid(userLoginDTO.getCode());
        String key = USER_LOGIN + openid;
        //判断id是否为·空
        if (openid == null) {
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
        }//获取用户id
        String userStrId = (redisTemplate.opsForValue().get(key));

        //如果是新用户 自动完成注册
        if (userStrId == null) {
            //无法反射到用户id 调用数据库
            User user = userMapper.getByOpenid(openid);
            //用户注册
            if (user == null) {
                user = User
                        .builder()
                        .openid(openid)
                        .createTime(LocalDateTime.now())
                        .status(User.STATUS_正常)
                        .build();
                int rows = userMapper.insertwx(user);
                if (rows != 1) { // 校验插入结果
                    log.error("新用户注册失败，openid:{}", openid);
                    throw new LoginFailedException(USER_REGISTER_ERROR);
                }
            }
            //封号的账号 不能正常使用
            Integer status = user.getStatus();
            if (status == User.STATUS_禁用) {
                throw new LoginFailedException(MessageConstant.ACCOUNT_LOCKED);
            }
            //更新永久层 保存
            try {
                redisTemplate.opsForValue().set(key,String.valueOf(user.getId()),10,TimeUnit.HOURS);
                redisTemplate.opsForValue().set(USER_INFO+user.getId(),objectMapper.writeValueAsString(user)
                        ,30, TimeUnit.MINUTES);
            } catch (Exception e) {
                log.error(e.getMessage());
                log.error("将用户id存入永久层失败");
            }
            //非null 返回
            return user;
        }
        //非null


        Long userId = null;
        try {
            userId = Long.valueOf(userStrId);
        } catch (NumberFormatException e) {

            throw new LoginFailedException("将sttring转为long时出现了问题");
        }
        // userStrid不为null 那么就是存了值 用户一定在数据库中 所以不处理null值
        User user = getCurrentUserByCacheOrDB(userId);
        if (user == null) {
            throw new LoginFailedException("未知逻辑异常");
        }
        try {
            String jsonUser = objectMapper.writeValueAsString(user);
            redisTemplate.opsForValue().set(USER_INFO+user.getId(), jsonUser, 30, TimeUnit.MINUTES);
        } catch (JsonProcessingException e) {
            log.error("用户 openid:{} 缓存序列化失败", openid, e);
            // 缓存失败不影响登录，但需记录日志
        }

        //返回这个用户对象
        return user;
    }

    /**
     * 根据用户ID获取用户信息
     * 优先从Redis缓存获取，缓存不存在则查询数据库并更新缓存
     *
     * @param userId 用户ID
     * @return 用户信息，不存在返回null 返回未null说明用户未注册
     */
    public User getCurrentUserByCacheOrDB(Long userId) {
        if (userId == null) {
            log.warn("用户ID为空");
            return null;
        }
        String key = USER_INFO + userId;
        String userStr;

        // 尝试从缓存获取
        try {
            userStr = redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            log.error("获取用户{}缓存异常", userId, e);
            userStr = null; // 缓存异常时直接查询数据库
        }

        // 缓存存在且有效
        if (userStr != null) {
            // 处理空值缓存
            if (userStr.equals("NULL")) {
                //说明数据库中也是不存在
                log.info("用户{}不存在（缓存命中）", userId);
                return null;
            }

            try {
                return objectMapper.readValue(userStr, User.class);
            } catch (JsonProcessingException e) {
                log.error("用户{}缓存数据解析失败，清除无效缓存", userId, e);
                redisTemplate.delete(key); // 删除无效缓存
            }
        }

        // 缓存未命中，查询数据库
        User user = userMapper.getById(userId);

        // 处理用户不存在的情况
        if (user == null) {
            log.info("用户{}未注册", userId);
            // 缓存空值，避免缓存穿透
            redisTemplate.opsForValue().set(key, "NULL", 300, TimeUnit.SECONDS);
            return null;
        }

        // 将数据库查询结果写入缓存
        try {
            redisTemplate.opsForValue().set(key, objectMapper.writeValueAsString(user),
                    30, TimeUnit.MINUTES); // 30分钟过期
        } catch (JsonProcessingException e) {
            log.error("用户{}缓存写入失败", userId, e);
            // 此处不抛出异常，避免影响主流程
        }

        return user;
    }


    private String getOpenid(String code) {
        Map<String, String> map = new HashMap<>();
        map.put("appid", Wxproperties.getAppid());
        map.put("secret", Wxproperties.getSecret());
        map.put("js_code", code);
        map.put("grant_type", "authorization_code");
        String json = HttpClientUtil.doGet(WX_LOGIN, map);

        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");
        String errcode = jsonObject.getString("errcode");
        log.info(errcode);
        return openid;
    }

    /**
     * 向用户qq邮箱发送验证码
     *
     * @param email
     */
    public void sendCode(String email) {
        //随机生成六位数验证码
        String code = RandomStringUtils.randomNumeric(6);
        try {
            sendArticleCommentMail(email + "@qq.com", code);
            log.info("向{}发送验证码为{}", email, code);
            String key = UserConstant.SEND_EMAIL + email;
            // TODO 测试时间 为100min
            redisTemplate.opsForValue().set(key, code, RedisConstant._CODE_EXPIRE_SECONDS * 100, TimeUnit.MINUTES);
            //发送验证码
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 注册功能
     *
     * @param registerDTO
     * @return
     */
//    public boolean register(RegisterDTO registerDTO) {
//        String code = registerDTO.getCode();
//        //验证码格式错误
//        if (code == null || code.length() != 6) {
//            return false;
//        }
//        //校验邮箱是否正确
//        boolean flag = validateQQEmail((registerDTO.getQq() + "@qq.com"));
//        if (!flag) {
//            return false;
//        }
//        //从redis中获取验证码
//        String registerCode = (String) redisTemplate.opsForValue().get(UserConstant.SEND_EMAIL + registerDTO.getQq());
//        //匹配通过
//        // 验证码通过 并且注册的邮箱不存在
//        if (registerCode.equals(code) && userMapper.selectByemail(registerDTO.getQq()) == null) {
//            ;
//            User user = new User();
//            BeanUtils.copyProperties(registerDTO, user);
//            user.setStatus(User.STATUS_正常);
//            userMapper.insertQQ(user);
//            log.info("成功注册用户{}", user.getQq());
//            return true;
//        } else {
//            return false;
//        }
//    }
//

    /**
     * 用户更新信息
     *
     * @param userUpdateDTO 更新的用户信息
     */
    public void updateUserInfo(UserUpdateDTO userUpdateDTO) {

        User userUpdate = new User();
        //TODO 测试数据
        BeanUtils.copyProperties(userUpdateDTO, userUpdate);

        //从当前线程中的获取用户id
        userUpdate.setId(BaseContext.getCurrentId());
        //从redis中获取用户信息
        User currentUserByCacheOrDB = getCurrentUserByCacheOrDB(userUpdate.getId());
        //数据库中不存在 一定用户不存在
        if (currentUserByCacheOrDB == null) {
            log.info("用户不存在");
            throw new BaseException("用户不存在");
        }
        //用户存在情况
//        private String username;
//        private Integer sex;
//        private Integer age;
//        private Integer height;
//        private List<String> prefer;
//        private float weight;
        currentUserByCacheOrDB.setUsername(userUpdate.getUsername());
        currentUserByCacheOrDB.setSex(userUpdate.getSex());
        currentUserByCacheOrDB.setAge(userUpdate.getAge());
        currentUserByCacheOrDB.setHeight(userUpdate.getHeight());
        if(userUpdateDTO.getPrefer()!=null)
        {try {
            currentUserByCacheOrDB.setFlavorPreference(objectMapper.writeValueAsString(userUpdateDTO.getPrefer()));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }}
        currentUserByCacheOrDB.setWeight(userUpdate.getWeight());

        String key = USER_INFO + userUpdate.getId();

        redisTemplate.delete(key);
        //更新数据库
        try {
            userMapper.update(currentUserByCacheOrDB);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BaseException("用户更新信息失败！");
        }
    }


//    /**
//     * 重置密码
//     * @param password
//     */
//    public void resetPassword(String password) {
//        String pw = PasswordEncoder.encode(password);
//        String logintype = BaseContext.getLoginType()+"_user";
//        Long id = BaseContext.getCurrentId();
//        id=1L;
//        User user = new User();
//        user.setId(id);
//        user.setPassword(pw);
//        userMapper.update(user);
//    }

//    @Override
//    public User qqlogin(UserLoginDTO userLoginDTO) {
//     User user= userMapper.getByQq(userLoginDTO.getQq());
//     if(user==null){
//         throw new LoginFailedException("用户不存在");
//     }
//        String password = user.getPassword();
//        String ps = DigestUtils.md5DigestAsHex(userLoginDTO.getPassword().getBytes());
//        //密码匹配不相同
//        if (!password.equals(ps)) {
//            throw new LoginFailedException("密码错误");
//        }
//        //账号被禁用登录不进进
//        if(user.getStatus()==User.STATUS_禁用){
//            throw  new LoginFailedException("账号被禁用，请联系管理员");
//        }
//        //没问题就返回用户实体类
//        return user;
//
//    }

    public Result forget(UserForgetDTO userForgetDTO) {
        Long id = BaseContext.getCurrentId();
        //从redis中获取用户验证码
      //  String key=
       // redisTemplate.opsForValue().get();
        //不存在 返回error
        //存在 校验验证码
        //不成功 返回erro
        //成功 加密密码 后更新数据库
        return null;
    }




    public UserLoginVO getUserInfo(Long id) {
        User user = getCurrentUserByCacheOrDB(id);
        if (user==null){
            throw new BaseException("用户为null");
        }
        List<String> userPrefers = List.of();
        if(user.getFlavorPreference()!= null)
        {try {
            userPrefers = objectMapper.readValue(user.getFlavorPreference(), new TypeReference<List<String>>() {
            });
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }}
        UserLoginVO userLoginVO = new UserLoginVO();
        BeanUtils.copyProperties(user, userLoginVO);
        userLoginVO.setUserPrefers(userPrefers);

        return userLoginVO;
    }

    @Override
    public List<User> getAllUsers() {
       List<User> users= userMapper.getAllUsers();
       return null;
    }


    public PageResult pageQuery(UserPageQueryDTO userPageQueryDTo) {
        if(userPageQueryDTo.getPage()<0){
            userPageQueryDTo.setPage(1);
        }
        if (userPageQueryDTo.getPageSize()<0||userPageQueryDTo.getPageSize()>20){
            userPageQueryDTo.setPageSize(10);
        }
        PageHelper.startPage(userPageQueryDTo.getPage(),userPageQueryDTo.getPageSize());
        Page page=userMapper.pageQuery(userPageQueryDTo);
        int total=(int) page.getTotal();
        List result = page.getResult();
        return new PageResult(total,result);
    }

    @Transactional
    public void updateUserStatus(Integer status, Long id) {
       User user=new User();
       user.setStatus(status);
       user.setId(id);
       redisTemplate.delete(USER_INFO + id);
        try {
            userMapper.update(user);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BaseException("修改用户状态失败");
        }
    }

    public void sendArticleCommentMail(String email,String code) {


        MimeMessage message = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            //邮件发件人
            helper.setFrom(sendMailer);
            //邮件收件人
            helper.setTo(email);
            //邮件主题
            helper.setSubject("酱梨健康：");
            //邮件内容
            helper.setText("许大王：您的验证码为"+code, true);
            //邮件发送时间
            helper.setSentDate(new Date());
            javaMailSender.send(message);
            //发送邮箱有@qq.com
            log.info("发送邮件成功:{}->{}", email);
        } catch (MessagingException e) {
            log.error("发送邮件时发生异常！", e);
        }
    }
}
